液晶表示器で文字表示してみよう!−−その2
(4ビットインターフェースデータ長の場合)

今度は液晶表示器を、4ビットインターフェースデータ長で動作させてみましょう。8ビットモードと比較して文字コードデータを上位下位4ビットに分けて制御させます。なお、PICとの接続ですが、8ビットと比べて配線数が少ない利点を生かして、単一ポートで制御させてみましょう。「PIC活用ハンドブック」のP.336に掲載されている内容では、PORTAとPORTBを使用していますが、ここではPORTBのみで動作させることにしましょう。


<項目>ハード側の接続
図1に液晶表示器とPIC間の接続回路例を示します。図1(a)はSC1602BSLB(16文字×2行)、(b)はSC2004C(20文字×4行)のSUNLIKE社製の液晶表示器を使いました。液晶表示器のコネクタ・ピン配置の項目を参照して確実に接続してください。
詳細はこちら→コネクタ・ピン配置について
特に電源端子ですが、同じSUNLIKE社製でありながら、VDDとVSSだけが逆になっています。もしも間違えると壊れる可能性大です。差し替えの際には十分注意してください。また、コントラスト調整電源端子(Vo)ですが、10kΩの可変抵抗器で0〜5Vの電圧を供給しています。Vo=0V(VSS)で最も濃くなります。可変抵抗器がなければ、とりあえずVo端子はVSSに接続しておいてください。
なお、4ビットモードでは液晶表示器のDB0〜DB3端子は未使用となっておりますが、必ずGNDに接続してください。液晶表示器の初期化の段階では8ビットモードになっており、DB0〜DB3ピンをLowレベルにしておきます。
ここがポイント
4ビットモードでは液晶表示器のDB0〜DB3端子は必ずGNDに接続すること
(注)オープンにしていると、初期化できない場合があります。

液晶表示器(16文字×2行)とPIC間の接続(4ビット・インターフェースデータ長の場合)
図1(a).液晶表示器(16文字×2行)とPIC間の接続
(4ビット・インターフェースデータ長の場合)


液晶表示器(20文字×4行)とPIC間の接続(4ビット・インターフェースデータ長の場合)
図1(b).液晶表示器(20文字×4行)とPIC間の接続
(4ビット・インターフェースデータ長の場合)



<項目>液晶表示動作の確認プログラム(2)
(4ビット・インターフェースデータ長の場合)


図3に液晶表示動作の確認プログラムのフローチャートを示します。
プログラムの解説については、「プログラムの説明」の項をご参照ください。

液晶表示動作の確認プログラム(2) フローチャート
液晶表示動作の確認プログラム(2) フローチャート
液晶表示動作の確認プログラム(2) フローチャート
液晶表示動作の確認プログラム(2) フローチャート
図3−1.液晶表示動作の確認プログラム(2)
フローチャート


LCD・コマンド出力サブルーチンのフローチャート(1)
LCD・文字データ出力サブルーチンのフローチャート(1)
図3−2(a).LCD・コマンド出力
4ビットモード対応の
サブルーチンのフローチャート


図3−3(a).LCD・文字データ出力
4ビットモード対応の
サブルーチンのフローチャート


LCD・コマンド出力サブルーチンのフローチャート(2) LCD・文字データ出力サブルーチンのフローチャート(2)
図3−2(b).LCD・コマンド出力部の
サブルーチンのフローチャート


図3−3(b).LCD・文字データ出力部の
サブルーチンのフローチャート


LCD・初期化サブルーチンのフローチャート
LCD・初期化サブルーチンのフローチャート
LCD・ビジーチェックサブルーチンのフローチャート
LCD・ビジーチェックサブルーチンのフローチャート
図3−4.LCD・初期化
サブルーチンのフローチャート
図3−5.LCD・ビジーチェック
サブルーチンのフローチャート

(注)以下に示すプログラムには、ホームページ画面作成の都合上、空白として全角文字のスペースなどが挿入されています。したがって、下記プログラムリストをそのままコピーしてMPLABのソースファイルとされた場合には、エラーとなることがあります。

→ここをクリックして、下記のプログラムをダウンロードするようにしてください。
  <ダウンロードする>ファイル名:「lcd_2.asm」 サイズ9.01kバイト

→ここをクリックして、下記のオブジェクトファイルをダウンロードするようにしてください。
  <ダウンロードする>ファイル名:「lcd_2.hex」 サイズ0.97kバイト

(注)下記のプログラムリストは、8ビットインターフェース長のプログラム(1)と比べて、おもに異なるところを青字で示しています。
なお、プログラムリストのコメントの番号ですが、8ビットインターフェース長のプログラムの説明と同等な箇所に、同じ番号を使っています。また、コメントの番号の数字の大小、順序は、特に意味はありません。

;***********************************************************
;
; 液晶表示器(LCD)テストプログラム(2)
; (4ビットインターフェースデータ長の場合)

;
; LCDの DB7〜DB4端子は、それぞれ PIC のRB4〜RB7端子に接続
; LCDの DB3〜DB0端子は、GNDに接続
; LCDの RS,R/W,E端子は、それぞれ PIC のRB2,RB1,RB0端子に接続

;
; テスト表示例は、下記の文字を表示するものとする。
;
; SPECTRUMホームへ゜ーシ゛
; 0123456789ABCDEF
;
;***********************************************************
    LIST   P=PIC16F877
    INCLUDE  P16F877.INC
;(1)プロセッサの種別指定
;(2)インクルードファイルの指定
;***********************************************************
; 変数定義とレジスタ割付
;***********************************************************
COUNT  EQU 20H
COUNT1 EQU 21H
COUNT2 EQU 22H
COUNT3 EQU 23H
COUNT4 EQU 24H
DPDT  EQU 25H
POINT  EQU 26H

RS   SET 2
RW   SET 1
E    SET 0

BUSY_F SET 7

    ORG 0
;(3)ループカウンタ
;   ループカウンタ1
;   ループカウンタ2
;   ループカウンタ3
;   ループカウンタ4
;   一時保存データ
;   テーブルポインタ
;
;   LCD レジスタ選択信号のビット番号
;   LCD 読み出し/書き込み選択信号のビット番号
;   LCD 動作起動信号のビット番号
;
;   LCD ビジーフラグのビット番号
;
;(4)プログラムの開始番地の指定
;***********************************************************
; 入出力ピン初期化
;***********************************************************
    BSF    STATUS,RP0
    CLRF   TRISB
    BCF    STATUS,RP0
;(5)Bank 1 へ切替
;
(8)全PortB 出力モードに設定
;(9)Bank 0 へ戻す
;***********************************************************
; メインプログラム
;***********************************************************
START
    CALL   LCD_INI

    CALL   
LCD_BUSY_4
    MOVLW   B'00001110'
    CALL   
LCD_CMD_4
    CALL   TIME1S
;
;(10)液晶表示器の初期化サブルーチンへ
;
;(11)BFチェック
;(12)表示ON、カーソルON
;(13)液晶表示器へコマンド出力
;(14)WAIT(1秒)

TEXT_OUT1
    CLRF   POINT
ROW_1
    MOVF   POINT,W
    CALL   TABLE
    ADDLW   0
    BTFSC   STATUS,Z
    GOTO   TEXT_OUT2
    CALL   
LCD_DATA_4
    CALL   TIME1S
    INCF   POINT,F
    GOTO   ROW_1


;(15)テーブルポインタのリセット
;(16)1行目のテキストデータ表示
;(17)テーブルポインタの値をWregへロードする(OFFSET)
;(18)テキストデータの読み込みサブルーチンへ
;(19)Wregレジスタに0を加算する
;   演算結果がゼロかチェック(テキストデータは「0」?)
;   テキストデータが終了のとき TEXT_OUT2へジャンプ
;   テキストデータをLCD出力するためサブルーチンへ
;(20)WAIT(1秒)
;(21)テーブルポインタ +1
;(22)ROW_1 のラベルへ戻り繰り返す

TEXT_OUT2
    INCF   POINT,F
    MOVLW   B'11000000'
    CALL   
LCD_CMD_4
    CALL   TIME1S


;(23)テーブルポインタ +1
;(24)カーソルが2行目にくるようにアドレスセット
;(25)液晶表示器へコマンド出力
;(26)WAIT(1秒)

ROW_2
    MOVF   POINT,W
    CALL   TABLE
    ADDLW   0
    BTFSC   STATUS,Z
    GOTO   TEXT_CLEAR
    CALL   
LCD_DATA_4
    CALL   TIME1S
    INCF   POINT,F
    GOTO   ROW_2

;(27)2行目のテキストデータ表示
;(28)テーブルポインタの値をWregへロードする(OFFSET)
;(29)テキストデータの読み込みサブルーチンへ
;(30)Wregレジスタに0を加算する
;   演算結果がゼロかチェック(テキストデータは「0」?)
;   テキストデータが終了のとき TEXT_CLEARへジャンプ
;   テキストデータをLCD出力するためサブルーチンへ
;(31)WAIT(1秒)
;(32)テーブルポインタ +1
;(33)ROW_2 のラベルへ戻り繰り返す

TEXT_CLEAR
    MOVLW   B'00000001'
    CALL   
LCD_CMD_4
    CALL   TIME1S
;
    GOTO   TEXT_OUT1


;(34)表示クリア
;(35)液晶表示器へコマンド出力
;(36)WAIT(1秒)

;(37)テキスト文字を繰り返し表示する

TABLE
    ADDWF   PCL,F
    DT "SPECTRUMホームページ",0 
    DT "0123456789ABCDEF",0 

;
;(38)PC+OFFSET
;
;   TABLEの定義(PC+OFFSET相当のデータを持って戻る)
;***********************************************************
; 液晶表示器の初期化サブルーチン    (39)
;***********************************************************
LCD_INI
    CALL   TIME10M
    CALL   TIME10M
    MOVLW   B'00110000'
    CALL   LCD_CMD

    CALL   TIME10M
    MOVLW   B'00110000'
    CALL   LCD_CMD

    CALL   TIME100
    MOVLW   B'00110000'
    CALL   LCD_CMD

    CALL   TIME100

    
MOVLW   B'00100000'
    CALL   LCD_CMD

    CALL   
LCD_BUSY_4
    
MOVLW   B'00101000'
    CALL   
LCD_CMD_4

    CALL   
LCD_BUSY_4
    MOVLW   B'00001000'
    CALL   
LCD_CMD_4

    CALL   
LCD_BUSY_4
    MOVLW   B'00000001'
    CALL   
LCD_CMD_4

    CALL   
LCD_BUSY_4
    MOVLW   B'00000110'

    CALL   
LCD_CMD_4

    RETURN

;(40)WAIT(10ms)
;   WAIT(10ms) 10ms×2=20msを確保(15ms以上)
;(41)ファンクションセット(8bitモードに設定)
;(42)液晶表示器へコマンド出力

;(43)WAIT(10ms)を確保(4.1ms以上)
;(44)ファンクションセット(8bitモードに設定)
;(45)液晶表示器へコマンド出力

;(46)WAIT(100μs)
;(47)ファンクションセット(8bitモードに設定)
;(48)液晶表示器へコマンド出力

;
(46')WAIT(100μs)
;
(47')ファンクションセット(4bitモード)
;(48')液晶表示器へコマンド出力

;
(49)ここからBFチェックができます
;
(50)ファンクションセット(4bitモード,1/16デューティ,5×7ドット)
;(51)液晶表示器へコマンド出力

;(52)BFチェック
;(53)表示オフ
;(54)液晶表示器へコマンド出力

;(55)BFチェック
;(56)表示クリア
;(57)液晶表示器へコマンド出力

;(58)BFチェック
;(59)エントリーモードセット
;   (アドレスを+1し、カーソルは右移動,表示シフトはしない)
;(60)液晶表示器へコマンド出力


;***********************************************************
; 液晶表示器へコマンドを出力するサブルーチン
;***********************************************************
LCD_CMD_4
    MOVWF   DPDT
    ANDLW   0F0H
    CALL   LCD_CMD
    SWAPF   DPDT,W
    ANDLW   0F0H
    CALL   LCD_CMD
    RETURN


LCD_CMD
    MOVWF   PORTB
    BCF    
PORTB,RW
    BCF    
PORTB,RS
    BSF    
PORTB,E
    NOP
    BCF    
PORTB,E
    RETURN
;(101)4ビットモード
;(102)データを一時保存
;(103)下位4ビットをマスクする
;(104)データ出力(コマンドコードの上位4ビット相当)
;(105)一時保存データの上位下位入れ替え
;(106)下位4ビットをマスクする
;(107)データ出力(コマンドコードの下位4ビット相当)


;(61)液晶表示器へコマンドを出力するサブルーチン
;
(62)DB4〜DB7(データバスの設定)
;(63)R/W = 0 (書き込みモードに設定)
;(64)RS = 0 (コマンドモードに設定)
;(65)E = 1 (動作起動信号の設定:Hでストローブ)
;(66)Eのパルス幅を220ns以上確保するためのダミー命令
;(67)E = 0 (動作起動信号の設定:Lに戻す)

;***********************************************************
; 液晶表示器へデータを出力するサブルーチン
;***********************************************************
LCD_DATA_4
    MOVWF   DPDT
    ANDLW   0F0H
    CALL   LCD_DATA
    SWAPF   DPDT,W
    ANDLW   0F0H
    CALL   LCD_DATA
    RETURN


LCD_DATA
    MOVWF   PORTB
    BCF    
PORTB,RW
    BSF    
PORTB,RS
    BSF    
PORTB,E
    NOP
    BCF    
PORTB,E
    RETURN
;(111)4ビットモード
;(112)データを一時保存
;(113)下位4ビットをマスクする
;(114)データ出力(文字コードの上位4ビット相当)
;(115)一時保存データの上位下位入れ替え
;(116)下位4ビットをマスクする
;(117)データ出力(文字コードの下位4ビット相当)



;(68)液晶表示器へデータを出力するサブルーチン
;
(69)DB4〜DB7(データバスの設定)
;(70)R/W = 0 (書き込みモードに設定)
;(71)RS = 1 (データモードに設定)
;(72)E = 1 (動作起動信号の設定:Hでストローブ)
;(73)Eのパルス幅を220ns以上確保するためのダミー命令
;(74)E = 0 (動作起動信号の設定:Lに戻す)
;
;***********************************************************
; ビジーチェック(BF)を行うサブルーチン
;***********************************************************
LCD_BUSY_4
    BSF    STATUS,RP0
    
MOVLW   0F0H
    MOVWF   TRISB
    BCF    STATUS,RP0
    BCF    
PORTB,RS
    BSF    
PORTB,RW
    BSF    
PORTB,E
    MOVF   PORTB,W
    BCF    
PORTB,E
    MOVWF   DPDT

    BSF    PORTB,E
    MOVF   PORTB,W
    BCF    PORTB,E


    BTFSC   DPDT,BUSY_F
    GOTO   
LCD_BUSY_4

    BCF    
PORTB,RW
    BSF    STATUS,RP0
    MOVLW   0H
    MOVWF   TRISB
    BCF    STATUS,RP0
    RETURN
;(75)ビジーチェック(BF)を行うサブルーチン
;(76)Bank 1 へ切替
;
(77)上位4ビットを入力モードに
;   PortB を設定
;(78)Bank 0 へ戻す
;(79)RS = 0 (コマンドモードに設定)
;(80)R/W = 1 (読み込みモードに設定)
;(81)E = 1 (動作起動信号の設定:Hでストローブ)
;(82)DDRAMからのデータ
(上位4ビット相当)の読み出し
;(83)E = 0 (動作起動信号の設定:Lに戻す)
;(84)読み込みデータをレジスタファイルに一時保存

;(81')E = 1 (動作起動信号の設定:Hでストローブ)
;(82')DDRAMからのデータ(下位4ビット相当)の読み出し
;(83')E = 0 (動作起動信号の設定:Lに戻す)


;(85)ビジーフラグのチェック(読み込みデータの7ビット目)
;   BUSY_F=1のとき
LCD_BUSY_4 間をループする
;   BUSY_F=0のときループを抜ける
;(86)R/W = 0 (書き込みモードに設定)
;(87)Bank 1 へ切替
;(88)出力モードに
;   PortB を設定
;(89)Bank 0 へ戻す
;
;***********************************************************
;遅延サブルーチン
;***********************************************************
;100μs遅延サブルーチン(20MHzクロック時)
;・・・・・ 別記プログラムリスト参照・・・・・
;
;10ms遅延サブルーチン(20MHzクロック時)
;・・・・・ 別記プログラムリスト参照・・・・・
;
;1s遅延サブルーチン(20MHzクロック時)
;・・・・・ 別記プログラムリスト参照・・・・・

    END


【プログラムの説明】ここがポイント
このプログラムについて、順を追って解説を加えておきましょう。

(1)プロセッサの種別指定
定義の仕方は「PROCESSOR」か「LIST」命令を使って設定します。ここで指定するプロセッサ名称は、パッケージの種類を示すサフィックス(最後の英記号の部分)は不要です。

   PROCESSOR  PIC16F877
    または
   LIST  P=PIC16F877

(2)標準ヘッダーファイルのインクルード
標準ヘッダーファイルとは、各プロセッサが持っているSFR(Special Function Register)をラベル(記号)で使える

ため、ラベルとハードウェアの場所とを定義しているファイルです。標準ヘッダーファイルは 「プロセッサ名.INC」というファイル名で統一されて、MPLABのディレクトリに格納されています。従って、これのインクルード方法は下記のようにして行います。
一度、参考までに標準ヘッダーファイルの内容をエディタ等で見ておくことをお勧めします。

   INCLUDE    P16F877.INC
    または
   #INCLUDE   P16F877.INC

(3)変数定義とレジスタ割付
レジスタファイルアドレスを指定するときに、アドレス数値を直接指定することもできますが、数値だけでは間違いも多く、プログラム自身も分かりにくくなってしまいます。そこで、EQU命令などを使ってラベルを設定し変数を定義します。レジスタファイルアドレスは、7ビットあるので、00〜7Fまで最大128個のレジスタが指定できますが、実際に物理的に実装されて汎用的に使用できるレジスタ数はデバイスによって異なっていますので注意が必要です。
PIC16F877の汎用レジスタのアドレスは、20H〜7FH
となっていますので、20H以降のアドレスに割り付けます。

(4)プログラムの開始番地の指定
「ORG」はプログラムの開始番地を指定する擬似命令で、ORG以下の実際のプログラム命令が格納されるプログラムメモリ内の位置(アドレス)を指定します。

   ORG  0  ;0番地から格納することを示します。

コンピュータは一般に電源投入時やリセットをすると必ず0番地からスタートするようになっているので、0番地には必ず命令があることが必要です。

(5)Bank 1 へ切替
PICには各種の動作モードを設定するための Special Register と呼ばれるものが用意されています。PICを動作させるためには、まずこのSpecial Registerの設定から始めます。そしてそれらは全て、Register File と呼ぶメモリとして用意されています。その Register Fileは Bank0, Bank1, Bank2, Bank3 とよばれるアドレス空間をもっているため、多少アクセスの仕方が面倒です。つまりRESET後の通常はBank0となっているので、Bank1側のレジスタにアクセスするときはBankの切替えをしてからとなります。またBank0とBank1に同じ物があるときにはどちらでも同じ様に使えます。
Bank1へ切り替える方法ですが、「STATUS」レジスタにある2ビットのRP0、RP1を変えてBankを指定します。デフォルトは、Bank0です。表1にBankとRP1,RP0ビットとの関係を示します。Bank1へ切り替えるためには、RP0ビットを「1」にします。(RP1はデフォルトで「0」なので変える必要はない。)

 BSF    STATUS,RP0
「STATUS」レジスタのRP0ビットを「1」にする。

表1.BankとRP1,RP0ビットとの関係
Bank RP1 RP0



(6)〜(7)PORTAは使用しないため、省略可

(8)PORTB 全ポートを出力に設定
TRISBレジスタを、CLRF(fレジスタをゼロクリアする命令)で出力設定とします。

 CLRF   TRISB
「TRISBレジスタをゼロクリアする。すなわち、PORTB全ポートを出力に設定する」

(9)Bank 0 へ戻す
Bank1での設定が終了した後は、Bank0に戻しておきます。Bank1へ切り替えるためには、RP0ビットを「0」にします。(RP1はデフォルトで「0」なので変える必要はない。)

BCF    STATUS,RP0
「STATUS」レジスタのRP0ビットを「0」にする。すなわち、Bank0に戻す。」

(10)液晶表示器の初期化サブルーチンへ
液晶表示器を使用する前に、初期化しておきます。ここでは、LCD_INIというラベルの付いたサブルーチンへジャンプします。

(11)BFチェック
液晶表示器の初期化が完了したかどうか確認のため、 Busy Flagのチェックをします。LCD_BUSY_4 というラベルの付いたサブルーチンへジャンプします。

(12)表示ON、カーソルON
液晶表示器の初期化後は、表示がOFFとなっているため、表示やカーソルの有無指定をします。
このインストラクションの詳細については、表示オン/オフコントロールを参照

(13)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMD_4 というラベルの付いたサブルーチンへジャンプします。

(14)WAIT(1秒)
液晶表示器の画面の変化が、人間の目で分かるように1秒間のウエイトを入れました。TIME1Sというラベルの付いたサブルーチンへジャンプします。

(15)テーブルポインタのリセット
POINTという変数を使い、表示させる文字列テーブルの文字位置を指し示すようにしました。最初の文字から表示させるため、ここでPOINT変数の値をクリアしておきます。

(16)1行目のテキストデータ表示
ここのラベル「ROW_1」以降のルーチンにより、液晶表示器の1行目にテキストを表示します。

(17)テーブルポインタの値をWregへロードする
文字列テーブルのポインタ値をワーキングレジスタへロードします。

(18)テキストデータの読み込みサブルーチンへ
表示させる文字列テーブル TABLEというラベルの付いたサブルーチンへジャンプします。

(19)Wregレジスタに0を加算する
   演算結果がゼロかチェック(テキストデータは「0」?)
   テキストデータが終了のとき TEXT_OUT2へジャンプ
   テキストデータがあればLCD出力するためのサブルーチンへ

テキストデータの読み込みサブルーチンから戻ってきたときに、ワーキングレジスタに文字コードを入れて戻ってきます。ただし、文字列の終了を判断するのに、”0”を使っています。ここでワーキングレジスタの内容が”0”であれば、演算結果が”0”になるのでゼロフラグが立ちます。一方、ワーキングレジスタの内容に文字コードが入っていれば、”0”を加算しても文字コードの値は変化しません。すなわち、表示する文字があればLCD_DATA_4 というサブルーチンへジャンプして表示し、終了すれば次の段階のTEXT_OUT2へジャンプする条件分岐を行っています。

(20)WAIT(1秒)
液晶表示器の画面の変化が、人間の目で分かるように1秒間のウエイトを入れました。TIME1Sというラベルの付いたサブルーチンへジャンプします。

(21)テーブルポインタ +1
次の文字表示を行うためテーブルポインタの値を+1します。テーブルポインタの値は、プログラムカウンタにテーブルポインタの値(OFFSET分)を足し合わせることで、表示文字が記載されたテーブルの位置関係を指し示すようになっています。

(22)ROW_1 のラベルへ戻り繰り返す
次の文字表示を行うため、ROW_1 のラベルへ戻り繰り返します。

(23)テーブルポインタ +1
2行目からの文字表示を行うためテーブルポインタの値を+1します。

(24)カーソルが2行目にくるようにアドレスセット
カーソルを2行目の先頭に来るように液晶表示器のアドレスをセットします。
アドレスの値は、40になります。詳細は液晶表示器の内部アドレスを参照してください。またアドレスセットのインストラクションについては、DDRAMアドレスセットを参照してください。 ここでは、B’11000000’になります。

(25)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMD_4 というラベルの付いたサブルーチンへジャンプします。

(26)WAIT(1秒)
液晶表示器の画面の変化が、人間の目で分かるように1秒間のウエイトを入れました。TIME1Sというラベルの付いたサブルーチンへジャンプします。

(27)2行目のテキストデータ表示
ここのラベル「ROW_2」以降のルーチンにより、液晶表示器の2行目にテキストを表示します。

(28)テーブルポインタの値をWregへロードする
文字列テーブルのポインタ値をワーキングレジスタへロードします。

(29)テキストデータの読み込みサブルーチンへ
表示させる文字列テーブル TABLEというラベルの付いたサブルーチンへジャンプします。

(30)Wregレジスタに0を加算する
   演算結果がゼロかチェック(テキストデータは「0」?)
   テキストデータが終了のとき TEXT_CLEARへジャンプ
   テキストデータがあればLCD出力するためのサブルーチンへ

テキストデータの読み込みサブルーチンから戻ってきたときに、ワーキングレジスタに文字コードを入れて戻ってきます。ただし、文字列の終了を判断するのに、”0”を使っています。ここでワーキングレジスタの内容が”0”であれば、演算結果が”0”になるのでゼロフラグが立ちます。一方、ワーキングレジスタの内容に文字コードが入っていれば、”0”を加算しても文字コードの値は変化しません。すなわち、表示する文字があればLCD_DATA_4 というサブルーチンへジャンプして表示し、終了すれば次の段階のTEXT_CLEARへジャンプする条件分岐を行っています。

(31)WAIT(1秒)
液晶表示器の画面の変化が、人間の目で分かるように1秒間のウエイトを入れました。TIME1Sというラベルの付いたサブルーチンへジャンプします。

(32)テーブルポインタ +1
次の文字表示を行うためテーブルポインタの値を+1します。テーブルポインタの値は、プログラムカウンタにテーブルポインタの値(OFFSET分)を足し合わせることで、表示文字が記載されたテーブルの位置関係を指し示すようになっています。

(33)ROW_2 のラベルへ戻り繰り返す
次の文字表示を行うため、ROW_2 のラベルへ戻り繰り返します。

(34)表示クリア
液晶表示器の2行目まで文字表示の終了後、1行目に戻って繰り返し表示を行うため、表示をクリアします。
このインストラクションの詳細については、表示クリアを参照

(35)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMD_4 というラベルの付いたサブルーチンへジャンプします。

(36)WAIT(1秒)
液晶表示器の画面の変化が、人間の目で分かるように1秒間のウエイトを入れました。TIME1Sというラベルの付いたサブルーチンへジャンプします。

(37)テキスト文字を繰り返し表示する
最初から文字表示を行うため、TEXT_OUT1のラベルへ戻り繰り返します。


(38)TABLEの定義(PC+OFFSET相当のデータを持って戻る)
    PC+OFFSET

データテーブルのサブルーチンに来ると、プログラムカウンタに、Wregの値(オフセット)が加算されます。その加算結果をプログラムカウンタとしますので、そのテーブルポインタ(アドレス)で指定されたデータを示すようになります。

ADDWF   PCL,F ;プログラムカウンタに、Wregの値(オフセット)を加算し、
             その加算結果をプログラムカウンタする。

(39)液晶表示器の初期化サブルーチン
詳細はインストラクションによる初期設定をご覧ください。


(40)WAIT(10ms)
   WAIT(10ms) 10ms×2=20msを確保(15ms以上)

液晶表示器の電源が4.5V以上に達してから、15ms以上のウエイトを入れます。ここでは10msのサブルーチンへ2回ジャンプすることで、20msを確保しています。

(41)ファンクションセット(8bitモードに設定)
このインストラクションの詳細については、ファンクションセットを参照

(42)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(43)WAIT(10ms)を確保(4.1ms以上)
上記のインストラクションの実行後、4.1ms以上のウエイトを入れます。ここでは10msのサブルーチンへジャンプすることで、10msを確保しています。

(44)ファンクションセット(8bitモードに設定)
このインストラクションの詳細については、ファンクションセットを参照

(45)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(46)WAIT(100μs)
上記のインストラクションの実行後、100μs以上のウエイトを入れます。ここでは100μsのサブルーチンへジャンプすることで、100μsを確保しています。

(47)ファンクションセット(8bitモードに設定)
このインストラクションの詳細については、ファンクションセットを参照

(48)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(46’)WAIT(100μs)
上記のインストラクションの実行後、100μs以上のウエイトを入れます。ここでは100μsのサブルーチンへジャンプすることで、100μsを確保しています。

(47’)ファンクションセット(4bitモードに設定)
このインストラクションの詳細については、ファンクションセットを参照

(48’)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(49)ここからBFチェックができます
上記のインストラクションが完了したかどうか確認のため、 Busy Flagのチェックをします。LCD_BUSY_4 というラベルの付いたサブルーチンへジャンプします。

(50)ファンクションセット(4bitモード,1/16デューティ,5×7ドット)
このインストラクションの詳細については、ファンクションセットを参照

(51)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMD_4 というラベルの付いたサブルーチンへジャンプします。

(52)BFチェック
上記のインストラクションが完了したかどうか確認のため、 Busy Flagのチェックをします。LCD_BUSY_4 というラベルの付いたサブルーチンへジャンプします。

(53)表示オフ
液晶表示器の初期化として表示をオフします。 このインストラクションの詳細については、表示オン/オフコントロールを参照

(54)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMD_4 というラベルの付いたサブルーチンへジャンプします。

(55)BFチェック
上記のインストラクションが完了したかどうか確認のため、 Busy Flagのチェックをします。LCD_BUSY_4 というラベルの付いたサブルーチンへジャンプします。

(56)表示クリア
液晶表示器の初期化として表示をクリアします。 このインストラクションの詳細については、表示クリアを参照

(57)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMD_4 というラベルの付いたサブルーチンへジャンプします。

(58)BFチェック
上記のインストラクションが完了したかどうか確認のため、 Busy Flagのチェックをします。LCD_BUSY_4 というラベルの付いたサブルーチンへジャンプします。

(59)エントリーモードセット
   アドレスを+1し、カーソルは右移動,表示シフトはしない)

液晶表示器の初期化としてエントリーモードをセットします。 このインストラクションの詳細については、エントリーモードセットを参照

(60)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMD_4 というラベルの付いたサブルーチンへジャンプします。

(101)液晶表示器へコマンドコードを出力するサブルーチン(4ビットモード)
4ビットモードでインストラクションを実行させるためのサブルーチンです。

(102)データを一時保存
DPDT変数にコマンドデータを格納しておきます。

(103)下位4ビットをマスクする
4ビットモードでインストラクションを実行させるため、下位4ビットをマスク(無効)にします。

(104)データ出力(コマンドコードの上位4ビット相当)
コマンドコードのデータを出力するサブルーチンへ

(105)一時保存データの上位下位入れ替え
DPDT変数に格納しておいたコマンドデータの上位下位を入れ替え、ワーキングレジスタに格納します。

(106)下位4ビットをマスクする
4ビットモードでインストラクションを実行させるため、下位4ビットをマスク(無効)にします。

(107)データ出力(コマンドコードの下位4ビット相当)
コマンドコードのデータを出力するサブルーチンへ

(61)液晶表示器へコマンドを出力するサブルーチン
インストラクションを実行させるためのサブルーチンです。各信号の制御関係については、制御信号のタイムチャートを参照してください。

(62)DB4〜DB7(データバスの設定)
インストラクションの設定データをRBポートに出力します。

(63)R/W = 0 (書き込みモードに設定)
リード/ライト選択信号(H=読み込み,L=書き込み)を書き込みモードに設定します。

(64)RS = 0 (コマンドモードに設定)
レジスタ選択信号、すなわちコマンド/データ選択(H=データ,L=コマンド)をコマンドモードに設定します。

(65)E = 1 (動作起動信号の設定:Hでストローブ)
動作起動信号をHレベルにして、各データをストローブします。

(66)Eのパルス幅を220ns以上確保するためのダミー命令
動作起動信号のパルス幅を220ns以上に確保するためにNOP命令を入れておきます。連続してON,OFFした場合、PIC命令の1サイクルの実行時間は、1サイクル実行時間=4/クロック周波数となっていますので、クロック周波数が20MHz(50ns)の場合は、4/20MHz=4*50ns=200nsとなります。1命令文で連続してON,OFFした場合、20MHzのクロック周波数では、十分なパルス幅を確保できません。したがって、間にNOP命令などを挿入して十分なパルス幅をとる必要があります。

(67)E = 0 (動作起動信号の設定:Lに戻す)
動作起動信号をLレベルにして、設定が完了します。

(111)液晶表示器へ文字コードを出力するサブルーチン(4ビットモード)
4ビットモードによる文字コード設定のためのサブルーチンです。

(112)データを一時保存
DPDT変数にコマンドデータを格納しておきます。

(113)下位4ビットをマスクする
4ビットモードによる文字コード設定のため、下位4ビットをマスク(無効)にします。

(114)データ出力(文字コードの上位4ビット相当)
文字コードのデータを出力するサブルーチンへ

(115)一時保存データの上位下位入れ替え
DPDT変数に格納しておいた文字コードデータの上位下位を入れ替え、ワーキングレジスタに格納します。

(116)下位4ビットをマスクする
4ビットモードによる文字コード設定のため、下位4ビットをマスク(無効)にします。

(117)データ出力(文字コードの下位4ビット相当)
文字コードのデータを出力するサブルーチンへ

(68)液晶表示器へデータを出力するサブルーチン
インストラクションを実行させるためのサブルーチンです。各信号の制御関係については、制御信号のタイムチャートを参照してください。

(69)DB4〜DB7(データバスの設定)
インストラクションの設定データをRBポートに出力します。

(70)R/W = 0 (書き込みモードに設定)
リード/ライト選択信号(H=読み込み,L=書き込み)を書き込みモードに設定します。

(71)RS = 1 (データモードに設定)
レジスタ選択信号、すなわちコマンド/データ選択(H=データ,L=コマンド)をデータモードに設定します。

(72)E = 1 (動作起動信号の設定:Hでストローブ)
動作起動信号をHレベルにして、各データをストローブします。

(73)Eのパルス幅を220ns以上確保するためのダミー命令
動作起動信号のパルス幅を220ns以上に確保するためにNOP命令を入れておきます。

(74)E = 0 (動作起動信号の設定:Lに戻す)
動作起動信号をLレベルにして、設定が完了します。

(75)ビジーチェック(BF)を行うサブルーチン
以前に受けたインストラクションによって、モジュールが内部動作中である間はループを繰り返し、インストラクションが完了するとメインルーチンへ戻るサブルーチンです。なお、制御信号の関係については、制御信号のタイムチャート(読み込み時)を参照してください。

(76)Bank 1 へ切替
RBポートを入力モードに設定するために、Bank1へ切り替えます。

(77)上位4ビットを入力モードに
液晶表示器のデータバスに接続されている端子(RB4〜RB7のポート)を入力モードに設定します。
TRISBレジスタの上位4ビットを”1”にすることで入力モードになります。下位3ビットは”0”で出力モード(RS,R/W,E)です。なお、RB3は未接続のため、入出力関係はどちらでもよいです。

(78)Bank 0 へ戻す
Bank1での設定が終了した後は、Bank0に戻しておきます。

(79)RS = 0 (コマンドモードに設定)
レジスタ選択信号、すなわちコマンド/データ選択(H=データ,L=コマンド)をコマンドモードに設定します。

(80)R/W = 1 (読み込みモードに設定)
リード/ライト選択信号(H=読み込み,L=書き込み)を読み込みモードに設定します。

(81)E = 1 (動作起動信号の設定:Hでストローブ)
動作起動信号をHレベルにして、各データをストローブします。

(82)DDRAMからのデータ(上位4ビット相当)の読み出し
RBポートからDDRAMの上位4ビット相当のデータを読み出します。

(83)E = 0 (動作起動信号の設定:Lに戻す)
動作起動信号をLレベルにして、設定が完了します。

(84)読み込みデータをレジスタファイルに一時保存
DPDT変数にデータを格納しておきます。

(81’)E = 1 (動作起動信号の設定:Hでストローブ)
動作起動信号をHレベルにして、各データをストローブします。

(82’)DDRAMからのデータ(下位4ビット相当)の読み出し
RBポートからDDRAMの下位4ビット相当のデータを読み出します。(注)ここでは読み出すという一連の動作が必要であって、読み出された下位4ビット相当のデータには、特に意味はありません。(ダミーデータの読み出し動作)

(83’)E = 0 (動作起動信号の設定:Lに戻す)
動作起動信号をLレベルにして、設定が完了します。

(85)ビジーフラグのチェック(読み込みデータの7ビット目)
    BUSY_F=1のときLCD_BUSY_4 間をループする
    BUSY_F=0のときループを抜ける

DPDT変数に格納されているデータの7ビット目がビジーフラグ(BF)です。このインストラクションの詳細については、ビジーフラグ/アドレス読み出しを参照してください。条件分岐は、BF=1のときループし、0のときループから抜け出るようになっています。

(86)R/W = 0 (書き込みモードに設定)
(80)でリード/ライト選択信号(H=読み込み,L=書き込み)を書き込みにモードに戻しておきます。

(87)Bank 1 へ切替
RBポートを出力モードに戻しておくために、Bank1へ切り替えます。

(88)出力モードにPortB を設定
TRISBレジスタの全ビットを”0”にすることで出力モードに設定します。

(89)Bank 0 へ戻す
Bank1での設定が終了した後は、Bank0に戻しておきます。


ポートの誤動作防止について
ここがポイント
BSF,BCFなどのビット操作命令で、同じポートに出力する場合には、間にダミーとしてNOP命令などを入れる
ここは、(63)〜(65)の各コマンド間、及び(70)〜(72)の各コマンド間、及び(79)〜(82)の各コマンド間のように、BSF,BCFなどのビット操作命令により同一ポートを続けて設定していると、ポートが誤動作をすることがあります。BSF,BCFなどのビット操作命令は、一度ポートレジスタのすべてのビットの状態を読み込み、指定ビットのみを変更して再度ポートレジスタに上書きするという操作がされます。すなわち、最初の命令 たとえば(63)の出力がなされ、次の命令(64)が出力される前に、一度入力動作があるのです。最初の命令の出力と次の命令の入力動作の間は、1クロック分しかなく、20MHzクロックの場合にはわずかに50nsecです。出力ピンの負荷に何らかの容量成分があると、信号の立ち上がりや立ち下がりが遅れるため、最初の命令の出力が完全に落ち着く前に次の命令で読み込みを実行してしまうため誤動作が発生しやすくなります。この対策としては、ビット操作命令で連続して同じポートに出力する場合には、間にNOP命令など他の命令を最低1個挿入するようにします。
(81)と(82)間についてもNOPを挿入しました。(2001.6.11 高山さんのメッセージを参照

;***********************************************************
; 液晶表示器へコマンドを出力するサブルーチン
;***********************************************************

・・・・・ 中略 ・・・・・

LCD_CMD
    MOVWF   PORTB
    BCF    
PORTB,RW
    NOP
    BCF    
PORTB,RS
    
NOP
    BSF    
PORTB,E
    NOP
    BCF    
PORTB,E
    RETURN
;(61)液晶表示器へコマンドを出力するサブルーチン
;
(62)DB4〜DB7(データバスの設定)
;(63)R/W = 0 (書き込みモードに設定)
; 誤動作防止のダミー命令
;(64)RS = 0 (コマンドモードに設定)
; 誤動作防止のダミー命令
;(65)E = 1 (動作起動信号の設定:Hでストローブ)
;(66)Eのパルス幅を220ns以上確保するためのダミー命令
;(67)E = 0 (動作起動信号の設定:Lに戻す)

;***********************************************************
; 液晶表示器へデータを出力するサブルーチン
;***********************************************************

・・・・・ 中略 ・・・・・

LCD_DATA
    MOVWF   PORTB
    BCF    
PORTB,RW
    
NOP
    BSF    
PORTB,RS
    
NOP
    BSF    
PORTB,E
    NOP
    BCF    
PORTB,E
    RETURN
;(68)液晶表示器へデータを出力するサブルーチン
;
(69)DB4〜DB7(データバスの設定)
;(70)R/W = 0 (書き込みモードに設定)
; 誤動作防止のダミー命令
;(71)RS = 1 (データモードに設定)
; 誤動作防止のダミー命令
;(72)E = 1 (動作起動信号の設定:Hでストローブ)
;(73)Eのパルス幅を220ns以上確保するためのダミー命令
;(74)E = 0 (動作起動信号の設定:Lに戻す)
;
;***********************************************************
; ビジーチェック(BF)を行うサブルーチン
;***********************************************************
LCD_BUSY_4
    BSF    STATUS,RP0
    
MOVLW   0F0H
    MOVWF   TRISB
    BCF    STATUS,RP0
    BCF    
PORTB,RS
    NOP
    BSF    
PORTB,RW
    NOP
    BSF    
PORTB,E
    
NOP
    MOVF   PORTB,W
    BCF    PORTB,E
    MOVWF   DPDT

    BSF    PORTB,E
    MOVF   PORTB,W
    BCF    PORTB,E


    BTFSC   DPDT,BUSY_F
    GOTO   
LCD_BUSY_4

    BCF    
PORTB,RW
    BSF    STATUS,RP0
    MOVLW   0H
    MOVWF   TRISB
    BCF    STATUS,RP0
    RETURN
;(75)ビジーチェック(BF)を行うサブルーチン
;(76)Bank 1 へ切替
;
(77)上位4ビットを入力モードに
;   PortB を設定
;(78)Bank 0 へ戻す
;(79)RS = 0 (コマンドモードに設定)
; 誤動作防止のダミー命令
;(80)R/W = 1 (読み込みモードに設定)
; 誤動作防止のダミー命令
;(81)E = 1 (動作起動信号の設定:Hでストローブ)
; 誤動作防止のダミー命令
;(82)DDRAMからのデータ
(上位4ビット相当)の読み出し
;(83)E = 0 (動作起動信号の設定:Lに戻す)
;(84)読み込みデータをレジスタファイルに一時保存

;(81')E = 1 (動作起動信号の設定:Hでストローブ)
;(82')DDRAMからのデータ(下位4ビット相当)の読み出し
;(83')E = 0 (動作起動信号の設定:Lに戻す)


;(85)ビジーフラグのチェック(読み込みデータの7ビット目)
;   BUSY_F=1のとき
LCD_BUSY_4 間をループする
;   BUSY_F=0のときループを抜ける
;(86)R/W = 0 (書き込みモードに設定)
;(87)Bank 1 へ切替
;(88)出力モードに
;   PortB を設定
;(89)Bank 0 へ戻す

;



<項目>液晶表示の動作確認
図4に(a)16文字×2行の液晶表示器での表示例、(b)20文字×4行の液晶表示器での表示例を示します。表示動作は、左上から「SPECTRUMホームヘ゜ーシ゛」と1秒おきに順に表示し、次に2行目に移って「0123456789ABCDEF」と順に表示していきます。表示が終わるとクリアされて最初からまた表示を繰り返します。
(注)図4の表示例は、2行目の「C」が表示された段階で撮影されたものです。制御はPORTBだけのため、8ビットモード時と比べて配線がスッキリしています。

16文字×2行の液晶表示器の例 20文字×4行の液晶表示器の例
図4(a).16文字×2行の
液晶表示器の例
図4(b).20文字×4行の
液晶表示器の例 




<戻る>
<TOPページへ>



楽天モバイル[UNLIMITが今なら1円] ECナビでポインと Yahoo 楽天 LINEがデータ消費ゼロで月額500円〜!


無料ホームページ 無料のクレジットカード 海外格安航空券 解約手数料0円【あしたでんき】 海外旅行保険が無料! 海外ホテル